﻿using EnvDTE;
using EnvDTE80;
using Microsoft.VisualStudio.Shell;
using QuickShare.Vsix.SqlList.Commons;
using System;
using System.ComponentModel.Design;
using System.IO;
using System.Linq;
using Task = System.Threading.Tasks.Task;

namespace QuickShare.Vsix.SqlList.Commands
{
    /// <summary>
    /// Command handler
    /// </summary>
    internal sealed class CommandAddToList
    {
        private DTE2 dte2;
        /// <summary>
        /// Command ID.
        /// </summary>
        public const int CommandId = 0x0101;

        /// <summary>
        /// Command menu group (command set GUID).
        /// </summary>
        public static readonly Guid CommandSet = new Guid("7ba8dde6-ac6b-47dd-9db8-b57a2c9e34a5");

        /// <summary>
        /// VS Package that provides this command, not null.
        /// </summary>
        private readonly AsyncPackage package;

        /// <summary>
        /// Initializes a new instance of the <see cref="CommandAddToList"/> class.
        /// Adds our command handlers for menu (commands must exist in the command table file)
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        /// <param name="commandService">Command service to add command to, not null.</param>
        private CommandAddToList(AsyncPackage package, OleMenuCommandService commandService)
        {
            this.package = package ?? throw new ArgumentNullException(nameof(package));
            commandService = commandService ?? throw new ArgumentNullException(nameof(commandService));
            var menuCommandID = new CommandID(CommandSet, CommandId);
            var menuItem = new OleMenuCommand(OnInvokedDynamicItem, null, OnBeforeQueryStatusDynamicItem, menuCommandID);
            commandService.AddCommand(menuItem);
            dte2 = (DTE2)this.ServiceProvider.GetServiceAsync(typeof(DTE)).Result;
        }
        private void OnBeforeQueryStatusDynamicItem(object sender, EventArgs args)
        {
            ThreadHelper.ThrowIfNotOnUIThread();
            OleMenuCommand menuCommand = (OleMenuCommand)sender;
            if(menuCommand == null)
            {
                return;
            }
            menuCommand.Enabled = true;
            foreach(SelectedItem item in dte2.SelectedItems)
            {
                if(item == null || !item.Name.EndsWith(".sql", StringComparison.OrdinalIgnoreCase))
                {
                    menuCommand.Visible = false;
                    return;
                }
            }
            menuCommand.Visible = true;
        }

        private async void OnInvokedDynamicItem(object sender, EventArgs args)
        {
            await Task.Run(async () =>
            {
                await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync();
                MenuCommand invokedCommand = (MenuCommand)sender;
                if(invokedCommand == null)
                    return;

                var project = await dte2.GetCurrentProject();
                if(project == null)
                {
                    var message = $"只能添加项目中~/{DTEHelper.SCRIPT_ROOT}文件夹内的脚本文件";
                    await dte2.WriteInConsole(message);
                    this.package.ShowMessage(message, "添加到执行列表失败");
                    return;
                }

                var items = await dte2.GetSelectedItemPaths();
                var list = items.Where(x => File.Exists(x)).ToList();
                using(var l = Lock.Get("添加执行列表"))
                {
                    if(l.IsSuccess)
                    {
                        try
                        {
                            var projectPath = Path.GetDirectoryName(project.FullName);
                            var rst = await DTEHelper.AddToListAsync(projectPath, dte2, project, list);

                            //var aletype = rst.IsSuccess ? __ACTIVITYLOG_ENTRYTYPE.ALE_INFORMATION : __ACTIVITYLOG_ENTRYTYPE.ALE_WARNING;
                            //VsShellUtilities.LogMessage("sqllist", rst.Message, aletype);
                            if(!rst.IsSuccess && !string.IsNullOrWhiteSpace(rst.Message))
                            {
                                this.package.ShowMessage(rst.Message, "添加到执行列表失败");
                            }
                            //else if(rst.IsSuccess && !string.IsNullOrWhiteSpace(rst.Message))
                            //{
                            //    this.package.ShowMessage(rst.Message, "添加到执行列表成功");
                            //}
                        }
                        catch(Exception ex)
                        {
                            var errorMessage = ex.AllMessage();
                            await dte2.WriteInConsole(errorMessage);
                            File.AppendAllText("sqllist-err.log",
                                            $"{DateTime.Now:yyyy-MM-dd HH:mm:ss:fff} 添加到执行列表失败：{Environment.NewLine}{errorMessage}{ex.StackTrace}");
                            this.package.ShowMessage(errorMessage, "添加到执行列表失败");
                        }
                    }
                    else
                    {
                        this.package.ShowMessage("正在执行以下操作：\r\n\t" + l.Message + "\r\n请稍候再试。", "提示");
                    }
                }
            });
        }

        /// <summary>
        /// Gets the instance of the command.
        /// </summary>
        public static CommandAddToList Instance
        {
            get;
            private set;
        }

        /// <summary>
        /// Gets the service provider from the owner package.
        /// </summary>
        private IAsyncServiceProvider ServiceProvider
        {
            get
            {
                return this.package;
            }
        }

        /// <summary>
        /// Initializes the singleton instance of the command.
        /// </summary>
        /// <param name="package">Owner package, not null.</param>
        public static async Task InitializeAsync(AsyncPackage package)
        {
            // Switch to the main thread - the call to AddCommand in Command1's constructor requires
            // the UI thread.
            await ThreadHelper.JoinableTaskFactory.SwitchToMainThreadAsync(package.DisposalToken);

            OleMenuCommandService commandService = await package.GetServiceAsync(typeof(IMenuCommandService)) as OleMenuCommandService;
            Instance = new CommandAddToList(package, commandService);
        }
    }
}
